package com.example.flutter_printer_plugin.inter

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.util.Base64
import android.util.Log
import com.example.flutter_printer_plugin.CodeUtils
import com.panling.printapi.MdUtils
import com.panling.printapi.Printer
import com.panling.printapi.Printer.BarcodeType
import com.panling.printapi.StringUtility

class PrintInterface {
    companion object{
        const val TAG = "PrintInterface"
        const val speed = 200
        const val maxWith = 380
        const val maxHeight = 480
        const val defaultInterval = 30
    }


    fun isSupportPrinter(): Boolean {
        return Printer.getInstance().platform
    }
    
    fun init() : Boolean{
        try {
            Log.d(TAG,"init start")
            val success = Printer.getInstance().init()
            if(success){
                Printer.getInstance().setFlowcontrol(1)
                Printer.getInstance().setPrintSpeed(speed)
            }
            Log.d(TAG,"success :$success")
            return success
        } catch (e: Exception) {
            Log.d(TAG,"init error:$e")
        }
        return false
    }

    fun free(): Boolean {
        return Printer.getInstance().free()
    }

    
    fun initPrint(){
       Printer.getInstance().initPrint()
    }

    
    fun sendData(content: String?): Int{
        return Printer.getInstance().sendData(content?.toByteArray())
    }

    
    fun printText(content: String?){
        Log.d(TAG,"printText :$content")
        Printer.getInstance().printText(content)
    }

    
    fun printText(content: String?, charsetName: String?){
        Log.d(TAG,"printText :$content ,charsetName:$charsetName")
        Printer.getInstance().printText(content, charsetName)
    }

    
    fun print(base64: String?, mode: Int, interval: Int,width:Int?,height:Int?){
        if (base64.isNullOrEmpty()) return
        Log.d(TAG,"print base64 :$base64")
        try {
            var requiredWidth = maxWith
            var requiredHeight = maxHeight
            var requiredInterval = defaultInterval
            width?.let {
                if(it!=0){
                    requiredWidth = Math.min(it,maxWith)
                }
            }
            height?.let {
                if(it!=0){
                    requiredHeight = Math.min(it,maxHeight)
                }
            }
            interval?.let {
                if(it!=0){
                    requiredInterval = it.coerceIn(defaultInterval, 100)
                }
            }
            val decodedBytes = Base64.decode(removeHeaderFromBase64(base64), Base64.DEFAULT)
            var bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.size),requiredWidth,requiredHeight,true)
            bitmap = MdUtils.convertToBlackAndWhite(bitmap)
            bitmap?.let {
                Printer.getInstance().printImage3(it,requiredInterval)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }


    private fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int {
        val height = options.outHeight
        val width = options.outWidth
        var inSampleSize = 1
        if (height > reqHeight || width > reqWidth) {
            val heightRatio = Math.ceil((height.toFloat() / reqHeight.toFloat()).toDouble()).toInt()
            val widthRatio = Math.ceil((width.toFloat() / reqWidth.toFloat()).toDouble()).toInt()
            inSampleSize = if (heightRatio < widthRatio) heightRatio else widthRatio
        }
        return inSampleSize
    }
    
    fun printImage(base64: String?,width:Int?,height:Int?){
        if (base64.isNullOrEmpty()) return
        try {
            var requiredWidth = maxWith
            var requiredHeight = maxHeight
            width?.let {
                if(it!=0){
                    requiredWidth = Math.min(it,maxWith)
                }
            }
            height?.let {
                if(it!=0){
                    requiredHeight = Math.min(it,maxHeight)
                }
            }
            val decodedBytes = Base64.decode(removeHeaderFromBase64(base64), Base64.DEFAULT)
            var bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.size),requiredWidth,requiredHeight,true)
            bitmap?.let {
                Printer.getInstance().printImage(it)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private fun removeHeaderFromBase64(base64String: String): String {
        val commaIndex = base64String.indexOf(",")
        return if (commaIndex != -1) {
            base64String.substring(commaIndex + 1)
        } else {
            base64String
        }
    }

    
    fun printBarcode(barcodeData: String?, barcodeType: String?){
        val type = when(barcodeType){
            BarcodeType.UPC_A.toString() -> BarcodeType.UPC_A
            BarcodeType.UPC_E.toString() -> BarcodeType.UPC_E
            BarcodeType.JAN8_EAN8.toString() -> BarcodeType.JAN8_EAN8
            BarcodeType.JAN13_EAN13.toString() -> BarcodeType.JAN13_EAN13
            BarcodeType.CODE39.toString() -> BarcodeType.CODE39
            BarcodeType.ITF_Interleaved_2_of_5.toString() -> BarcodeType.ITF_Interleaved_2_of_5
            BarcodeType.CODABAR_NW_7.toString() -> BarcodeType.CODABAR_NW_7
            BarcodeType.CODE93.toString() -> BarcodeType.CODE93
            BarcodeType.CODE128.toString() -> BarcodeType.CODE128
            BarcodeType.UCC_EAN128.toString() -> BarcodeType.UCC_EAN128
            else -> null
        }
        Log.d(TAG,"printBarcode type:$type")
        var barcodeType = 0
        if(barcodeData?.isNotEmpty()==true && barcodeData.isNotBlank()){
            val data = barcodeData.toByteArray()
            val length = barcodeData.toByteArray().size
            if(type == BarcodeType.UPC_A){
                if(length != 11 || !StringUtility.isDecimal(barcodeData)){
                    Log.e(TAG,"不是有效数据！有效数据规则:字符数11,只能输入0~9的数字")
                } else{
                    barcodeType = 0
                }
            } else if(type == BarcodeType.JAN8_EAN8){
                if(length != 7 || !StringUtility.isDecimal(barcodeData)){
                    Log.e(TAG,"不是有效数据！有效数据规则:字符数7,只能输入0~9的数字")
                }else{
                    barcodeType = 1
                }
            } else if(type == BarcodeType.JAN13_EAN13){
                if(length != 12 || !StringUtility.isDecimal(barcodeData)){
                    Log.e(TAG,"不是有效数据！有效数据规则:字符数12,只能输入0~9的数字")
                }else{
                    barcodeType = 2
                }
            } else if(type == BarcodeType.CODE39){
                for (k in data.indices) {
                    val d: Int = data[k].toInt()
                    if ((d in 48..57) || (d in 65..90) || d == 32 || d == 36 || d == 37 || (d in 42..47 && d!= 44)) {
                        barcodeType = 3
                    } else {
                        Log.e(TAG,"不是有效数据！有效数据规则:字符数1~24,范围0~9、A~Z、空、$、%、+、-、。、/")
                    }
                }
            } else if(type == BarcodeType.ITF_Interleaved_2_of_5){
                if (length < 2 || length > 255 || length % 2 != 0 || !StringUtility.isDecimal(barcodeData)) {
                    Log.e(TAG,"输入长度只能为小于等于24位数字的偶数,范围0~9")
                } else {
                    barcodeType = 4
                }
            } else if(type == BarcodeType.CODE128){
                if (length < 1 || length > 255) {
                    Log.e(TAG,"输入长度只能为1~30位字符，不包括汉字")
                }
                for (k in data.indices) {
                    val d = data[k].toInt() and 0xFF
                    if ((d < 0 || d > 127) && (d < 193 || d > 196)) {
                        Log.e(TAG,"不是有效数据！")
                    }
                }
                barcodeType = 5
            } else {
                barcodeType = 6
            }
        }
        Log.d(TAG,"printBarcode barcodeType:$barcodeType")
        try {
            when (barcodeType) {
                0 -> Printer.getInstance().printBarcode(barcodeData, BarcodeType.UPC_A)
                1 -> Printer.getInstance().printBarcode(barcodeData, BarcodeType.JAN8_EAN8)
                2 -> Printer.getInstance().printBarcode(barcodeData, BarcodeType.JAN13_EAN13)
                3 -> Printer.getInstance().printBarcode(barcodeData, BarcodeType.CODE39)
                4 -> Printer.getInstance().printBarcode(barcodeData, BarcodeType.ITF_Interleaved_2_of_5)
                5 -> Printer.getInstance().printBarcode(barcodeData, BarcodeType.CODE128)
                6 -> {
                    //Printer.getInstance().print(barcodeData, Printer.BarcodeType.QR_CODE);
                    Log.d(TAG, "Printer.BarcodeType.QR_CODE====$barcodeData")
                    val bitmap = CodeUtils.generateBitmap(barcodeData, 320, 320)
                    Printer.getInstance().printImage(bitmap)
                }
            }
        } catch (e: Exception) {
            Log.d(TAG, "printBarcode error--------${e.message}")
        }
    }

    
    fun setFeedRow(type: Int, n: Int){
        Printer.getInstance().setFeedRow(type, n)
    }

    
    fun setGSPMode(x: Int, y: Int){
        Printer.getInstance().setGSPMode(x, y)
    }

    
    fun setPrintRowSpacing(spacing: Int){
        Printer.getInstance().setPrintRowSpacing(spacing)
    }

    
    fun setPrintLeftMargin(nl: Int, nh: Int){
        Printer.getInstance().setPrintLeftMargin(nl, nh)
    }

    
    fun setPrintAlignmentMode(n: Int){
        Printer.getInstance().setPrintAlignmentMode(n)
    }

    
    fun setPrintSpeed(speed: Int){
        Printer.getInstance().setPrintSpeed(speed)
    }

    
    fun setPrintChromaLevel(chroma: Int){
        Printer.getInstance().setPrintChromaLevel(chroma)
    }

    
    fun restoreDefault(){
        Printer.getInstance().restoreDefault()
    }

    fun Black_label_On(){
        Printer.getInstance().Black_label_On()
    }

    fun Black_label_Off(){
        Printer.getInstance().Black_label_Off()
    }

    fun Feed_to_Next(){
        Printer.getInstance().Feed_to_Next()
    }

    
    fun setBarcodeHeight(height: Int){
        Printer.getInstance().setBarcodeHeight(height)
    }

    
    fun setBarcodeWidth(width: Int){
        Printer.getInstance().setBarcodeWidth(width)
    }

    
    fun setBarcodeHRI(position: Int){
        Printer.getInstance().setBarcodeHRI(position)
    }

    
    fun setUnderlineMode(n: Int){
        Printer.getInstance().setUnderlineMode(n)
    }

    
    fun setBoldMode(n: Int){
        Printer.getInstance().setBoldMode(n)
    }

    
    fun setFontDimension(n: Int){
        Printer.getInstance().setFontDimension(n)
    }

    
    fun getBaudRate():String{
        return Printer.getInstance().baudRate
    }

    
    fun Restore_factory(n: Int){
       Printer.getInstance().Restore_factory(n)
    }

    
    fun getVersion(): String{
       return Printer.getInstance().version
    }

    
    fun getFontVersion(): String{
        return Printer.getInstance().fontVersion
    }
}